package com.senlingspace.system.service.impl;

import com.alibaba.fastjson2.JSON;
import com.google.common.base.Splitter;
import com.google.common.base.Stopwatch;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.senlingspace.common.core.dingtalk.DingTalkService;
import com.senlingspace.common.core.domain.AjaxResult;
import com.senlingspace.common.core.redis.RedisCache;
import com.senlingspace.common.enums.*;
import com.senlingspace.common.request.PaymentRequest;
import com.senlingspace.common.utils.DateUtils;
import com.senlingspace.common.utils.NumberGenerator;
import com.senlingspace.common.utils.StringUtils;
import com.senlingspace.system.domain.*;
import com.senlingspace.system.domain.vo.MiniAppCartUpdateVo;
import com.senlingspace.system.domain.vo.MiniAppCartVo;
import com.senlingspace.system.domain.vo.MiniAppConfirmOrderRequest;
import com.senlingspace.system.mapper.*;
import com.senlingspace.system.service.ISlkjShoppingCartService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 购物车服务实现
 *
 * @author lebronjames
 * @date 2024/10/03
 */
@AllArgsConstructor
@Slf4j
@Service
public class SlkjShoppingCartServiceImpl implements ISlkjShoppingCartService {

    private static final String INCR_ORDER_NUMBER_PREFIX = "incr_order_number:";
    private static final String SHOPPING_CART_KEY = "shopping_cart_order_number:";

    private final RedisCache redisCache;
    private final DingTalkService dingTalkService;

    private final SlkjShoppingCartMapper slkjShoppingCartMapper;
    private final SlkjProductMapper slkjProductMapper;
    private final SlkjShopMapper slkjShopMapper;
    private final SlkjShopProjectMapper slkjShopProjectMapper;
    private final ProjectMapper projectMapper;
    private final SlkjOrderMapper slkjOrderMapper;
    private final SlkjOrderStatusLogMapper slkjOrderStatusLogMapper;
    private final SlkjOrderPricingSnapshotMapper slkjOrderPricingSnapshotMapper;


    @Override
    public AjaxResult addCart(MiniAppCartVo request, Long customerId, Long shopId) {
        SlkjProduct product = slkjProductMapper.selectSlkjProductByProductId(request.getProductId());
        if (product == null) {
            return AjaxResult.error("商品不存在！");
        }
        if ("1".equals(product.getAppStatus()) || "1".equals(product.getDelFlag())) {
            return AjaxResult.error("商品已下架！");
        }

        SlkjShoppingCart queryCart = new SlkjShoppingCart();
        queryCart.setCustomerId(customerId);
        queryCart.setProductId(request.getProductId());
        queryCart.setStatus((byte) 0);
        queryCart.setAttribute(request.getAttribute());
        SlkjShoppingCart cart = slkjShoppingCartMapper.selectByCustomerId(queryCart);

        int count;
        if (Objects.nonNull(cart)) {
            log.info("购物车中已存在该商品，数量增加：{}", request.getQuantity());
            cart.setQuantity(cart.getQuantity() + request.getQuantity());
            cart.setUpdatedAt(DateUtils.getNowDate());
            count = slkjShoppingCartMapper.update(cart);
        } else {
            log.info("购物车中不存在该商品，添加购物车：{}", JSON.toJSONString(request));
            SlkjShoppingCart shoppingCart = getSlkjShoppingCart(request, customerId, product);
            log.info("添加购物车，入库数据：{}", JSON.toJSONString(shoppingCart));
            count = slkjShoppingCartMapper.insert(shoppingCart);
        }

        return count > 0 ? AjaxResult.success("添加成功！") : AjaxResult.error("添加失败！");
    }

    @Override
    public List<SlkjShoppingCart> findByCustomerId(Long customerId) {
        List<SlkjShoppingCart> shoppingCartList = slkjShoppingCartMapper.findByCustomerId(customerId);
        log.info("用户 [{}] 购物车结果集：{}", customerId, JSON.toJSONString(shoppingCartList));
        return shoppingCartList;
    }

    @Override
    public AjaxResult updateCart(MiniAppCartUpdateVo request, Long customerId, Long shopId) {
        if (request.getType() == null) {
            return AjaxResult.error("参数错误！");
        }

        SlkjShoppingCart cart = slkjShoppingCartMapper.findById(request.getId());

        SlkjProduct product = slkjProductMapper.selectSlkjProductByProductId(cart.getProductId());
        if (product == null) {
            return AjaxResult.error("商品不存在！");
        }

        switch (request.getType()) {
            case ADD:
                if ("1".equals(product.getAppStatus()) || "1".equals(product.getDelFlag())) {
                    return AjaxResult.error("商品已下架！");
                }

                int total = request.getQuantity();
                if (total > product.getNumber()) {
                    return AjaxResult.error("商品库存不足！");
                }
                cart.setQuantity(total);
                cart.setUpdatedAt(DateUtils.getNowDate());
                slkjShoppingCartMapper.update(cart);
                return AjaxResult.success("更新成功！");
            case REDUCE:
                if ("1".equals(product.getAppStatus()) || "1".equals(product.getDelFlag())) {
                    return AjaxResult.error("商品已下架！");
                }

                int sum = request.getQuantity();
                if (sum > product.getNumber()) {
                    return AjaxResult.error("商品库存不足！");
                }
                cart.setQuantity(sum <= 0 ? 1 : sum);
                cart.setUpdatedAt(DateUtils.getNowDate());
                slkjShoppingCartMapper.update(cart);
                return AjaxResult.success("更新成功！");
            case DELETE:
                cart.setStatus((byte) 1);
                cart.setUpdatedAt(DateUtils.getNowDate());
                slkjShoppingCartMapper.update(cart);
                return AjaxResult.success("删除成功！");
            default:
                return AjaxResult.error("参数错误！");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public AjaxResult confirmOrder(MiniAppConfirmOrderRequest request, Long customerId, Long shopId, String customerPhone) {
        log.info("小程序购物车确认下单：request = {}, customerId = {}, shopId = {}", JSON.toJSONString(request), customerId, shopId);
        log.info("验证参数...");
        Stopwatch stopwatch = Stopwatch.createStarted();
        if (customerId == null || shopId == null || request == null) {
            return AjaxResult.error("参数错误！");
        }

        String cartIds = request.getCartIds();
        Long goodsId = request.getGoodsId();
        Integer buyQuantity = request.getBuyQuantity();
        String attribute = request.getAttribute();

        if (StringUtils.isBlank(cartIds) && Objects.isNull(goodsId)) {
            return AjaxResult.error("参数错误！");
        }

        long[] cartIdList = null;
        List<SlkjShoppingCart> cartList;
        if (StringUtils.isNotBlank(cartIds)) {
            log.info("用户通过购物车下单！");
            cartIdList = Splitter.on(",")
                    .trimResults()
                    .omitEmptyStrings()
                    .splitToList(cartIds).stream()
                    .mapToLong(Long::parseLong)
                    .toArray();

            if (cartIdList.length == 0) {
                return AjaxResult.error("购物车为空！");
            }

            cartList = slkjShoppingCartMapper.findByIds(cartIdList);
            if (CollectionUtils.isEmpty(cartList)) {
                return AjaxResult.error("购物车为空！");
            }

            for (SlkjShoppingCart cart : cartList) {
                // 查询商品信息
                SlkjProduct product = slkjProductMapper.selectSlkjProductByProductId(cart.getProductId());
                if (product == null) {
                    return AjaxResult.error("商品不存在！");
                }

                // 检查商品状态
                if ("1".equals(product.getAppStatus()) || "1".equals(product.getDelFlag())) {
                    return AjaxResult.error("商品已下架！");
                }

                // 检查购物车商品状态是否已删除
                if (cart.getStatus() == 1) {
                    return AjaxResult.error("购物车商品已删除！");
                }

                // 校验购物车用户
                if (!customerId.equals(cart.getCustomerId())) {
                    return AjaxResult.error("非法操作！");
                }
            }
        } else {
            log.info("用户直接购买商品！");
            if (StringUtils.isBlank(attribute)) {
                return AjaxResult.error("商品规格不能为空！");
            }

            if (buyQuantity == null || buyQuantity <= 0 || Objects.isNull(goodsId)) {
                return AjaxResult.error("参数错误！");
            }

            SlkjProduct product = slkjProductMapper.selectSlkjProductByProductId(goodsId);
            if (product == null) {
                return AjaxResult.error("商品不存在！");
            }

            if ("1".equals(product.getAppStatus()) || "1".equals(product.getDelFlag())) {
                return AjaxResult.error("商品已下架！");
            }

            cartList = Lists.newArrayList();
            SlkjShoppingCart shoppingCart = new SlkjShoppingCart();
            shoppingCart.setCustomerId(customerId);
            shoppingCart.setProductId(product.getProductId());
            shoppingCart.setProductName(product.getName());
            shoppingCart.setProductImage(product.getProductImg());
            shoppingCart.setProductPrice(product.getPrice().intValue());
            shoppingCart.setQuantity(buyQuantity);
            shoppingCart.setAttribute(attribute);
            shoppingCart.setGoodsCostPrice(product.getPrincipal());
            cartList.add(shoppingCart);
        }

        log.info("开始生成订单...");
        SlkjOrder order = getSlkjOrder(customerId, shopId, cartList, customerPhone);
        log.info("生成订单：{}", JSON.toJSONString(order));
        slkjOrderMapper.insertSlkjOrder(order);

        log.info("开始生成订单状态...");
        SlkjOrderStatusLog statusLog = getSlkjOrderStatusLog(order);
        log.info("生成订单状态日志：{}", JSON.toJSONString(statusLog));
        slkjOrderStatusLogMapper.insert(statusLog);

        log.info("开始生成订单商品价格快照...");
        List<SlkjOrderPricingSnapshot> pricingSnapshots = getSnapshots(cartList, order);
        log.info("插入商品价格快照：{}", JSON.toJSONString(pricingSnapshots));

        int insert = slkjOrderPricingSnapshotMapper.batchInsert(pricingSnapshots);
        if (insert != pricingSnapshots.size()) {
            log.error("小程序商品订单生成失败，系统执行回滚！");
            dingTalkService.sendTextMessage("小程序商品订单创建失败，主因：订单价格快照插入失败。系统执行回滚！order=" + JSON.toJSONString(order) + ", snaps=" + JSON.toJSONString(pricingSnapshots), true);
            throw new RuntimeException("系统异常，请重新下单！");
        }

        if (cartIdList != null) {
            redisCache.setCacheObject(SHOPPING_CART_KEY + order.getOrderNumber(), cartIds, 15, TimeUnit.MINUTES);
        }

        log.info("下单成功，共耗时: {}！", stopwatch.stop());
        return AjaxResult.success("下单成功！", order.getOrderId());
    }

    private List<SlkjOrderPricingSnapshot> getSnapshots(List<SlkjShoppingCart> cartList, SlkjOrder order) {
        log.info("cartList信息 = {}", JSON.toJSONString(cartList));
        List<SlkjOrderPricingSnapshot> pricingSnapshots = Lists.newArrayList();
        List<Long> productIds = cartList.stream().map(SlkjShoppingCart::getProductId).collect(Collectors.toList());
        Map<Long, SlkjProduct> productMap = slkjProductMapper.selectProductByProductIds(productIds)
                .stream()
                .collect(Collectors.toMap(SlkjProduct::getProductId, Function.identity()));
        SlkjOrderPricingSnapshot snapshot;
        for (SlkjShoppingCart cart : cartList) {
            snapshot = new SlkjOrderPricingSnapshot();
            snapshot.setOrderId(order.getOrderId());
            snapshot.setQuantity(1);
            snapshot.setItemType(PaymentRequest.GOODS);

            snapshot.setGoodsId(cart.getProductId());
            snapshot.setGoodsName(productMap.get(cart.getProductId()).getName());
            snapshot.setGoodsPrice(cart.getProductPrice());
            snapshot.setGoodsCostPrice(cart.getGoodsCostPrice());
            snapshot.setBayQuantity(cart.getQuantity());
            snapshot.setUserActualAmount(cart.getProductPrice() * cart.getQuantity());
            snapshot.setAttribute(cart.getAttribute());
            pricingSnapshots.add(snapshot);
        }
        return pricingSnapshots;
    }

    private static SlkjOrderStatusLog getSlkjOrderStatusLog(SlkjOrder order) {
        SlkjOrderStatusLog statusLog = new SlkjOrderStatusLog();
        statusLog.setOrderId(order.getOrderId());
        statusLog.setStatus(order.getGoodsStatus());
        statusLog.setChangeBy(Long.parseLong(order.getCreateBy()));
        statusLog.setChangeTime(order.getCreateTime());
        return statusLog;
    }

    private SlkjOrder getSlkjOrder(Long customerId, Long shopId, List<SlkjShoppingCart> cartList, String customerPhone) {
        // 构建订单
        SlkjOrder order = new SlkjOrder();
        SlkjShop shop = slkjShopMapper.selectSlkjShopByShopId(shopId);
        order.setShopId(shop.getShopId());
        order.setShopName(shop.getShopName());
        order.setSource(OrderSource.MINI_PROGRAM.getCode());
        SlkjShopProject shopProject = slkjShopProjectMapper.selectCurrentShowingProjectByShopId(shopId);
        order.setProjectId(shopProject.getProjectId());
        Project project = projectMapper.selectProjectByProjectId(shopProject.getProjectId());
        order.setProjectName(project.getName());
        order.setVerifyCode(NumberGenerator.getCharacters(7));
        order.setCreateBy(customerPhone);
        order.setCustomerId(customerId);
        order.setCreateTime(DateUtils.getNowDate());
        order.setOrderNumber(generateOrderNumber(order.getShopId(), order.getSource(), order.getCreateTime()));
        order.setOrderType(OrderType.OT_102.getCode());
        // 订单总额
        int totalAmount = cartList.stream()
                .mapToInt(cart -> cart.getQuantity() * cart.getProductPrice())
                .sum();
        order.setTotalAmount(totalAmount);
        order.setDiscountAmount(0);
        order.setActualAmount(totalAmount);
        order.setPaymentType(LakalaPaymentTypeEnum.WECHAT.getCode());
        // 待支付
        order.setGoodsStatus(GoodsStatusEnum.PENDING_PAYMENT.name());
        order.setPaymentStatus(LakalaTradeStateEnum.INIT.name());
        // 设置支付请求ID
        order.setPaymentRequestId(NumberGenerator.getCharacters(23));
        return order;
    }

    private static SlkjShoppingCart getSlkjShoppingCart(MiniAppCartVo request, Long customerId, SlkjProduct product) {
        SlkjShoppingCart shoppingCart = new SlkjShoppingCart();
        shoppingCart.setCustomerId(customerId);
        shoppingCart.setProductId(request.getProductId());
        shoppingCart.setProductName(product.getName());
        shoppingCart.setProductImage(product.getProductImg());
        shoppingCart.setProductPrice(product.getPrice().intValue());
        shoppingCart.setQuantity(request.getQuantity());
        shoppingCart.setAddedAt(DateUtils.getNowDate());
        shoppingCart.setStatus((byte) 0);// 正常
        shoppingCart.setIsChecked((byte) 1);// 选中
        shoppingCart.setIsExpired((byte) 0);// 未过期
        shoppingCart.setUpdatedAt(DateUtils.getNowDate());
        shoppingCart.setProductAttributes("");
        shoppingCart.setAttribute(request.getAttribute());
        return shoppingCart;
    }

    // 生成订单号
    private synchronized String generateOrderNumber(Long shopId, Integer source, Date createTime) {
        StringBuilder sb = new StringBuilder();
        // 前缀
        String prefix = Strings.padStart(String.valueOf(shopId), 3, '0');
        sb.append(prefix);

        // 时间
        String time = DateUtils.parseDateToStr(DateUtils.YYYYMMDD, createTime);
        sb.append(time);

        // 渠道
        sb.append(source);

        // 增量流水号
        Long incr;
        String key = INCR_ORDER_NUMBER_PREFIX + time + ":" + shopId;
        if (redisCache.hasKey(key)) {
            incr = redisCache.incr(key);
        } else {
            // 24小时内，重置流水号
            incr = redisCache.incr(key, 24, TimeUnit.HOURS);
        }
        if (Objects.isNull(incr)) {
            // 补偿机制
            // 如果获取不到，则生成随机流水号
            String number = NumberGenerator.getCharacters(5);
            sb.append(number);
        } else {
            sb.append(Strings.padStart(String.valueOf(incr), 5, '0'));
        }
        return sb.toString();
    }

}
